package com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.globals;

import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.nulldev.util.JVM.Arguments;
import com.nulldev.util.VariableAPI.RandomUtil;
import com.nulldev.util.data.FastMath.FastMath;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.BaseJSEnvironment;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.BaseJSObject;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.BaseJSVariable;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.global.BaseJSGlobalVariable;
import com.nulldev.util.scripting.ScriptAPI.baseJS.legacy.lexer.global.BaseJSNativeFunction;

public class BaseJSMath extends BaseJSObject {

	@SuppressWarnings("static-access")
	public static final BaseJSVariable PI = new BaseJSGlobalVariable("PI", FastMath.get().PI);
	@SuppressWarnings("static-access")
	public static final BaseJSVariable E = new BaseJSGlobalVariable("E", FastMath.get().E);
	public static final BaseJSNativeFunction random = new BaseJSNativeFunction("random") {
		private final boolean USE_FAST_RANDOM = Arguments.hasArgument("--BaseJS.useFastRandom");

		@Override
		public Object invoked(BaseJSEnvironment e, BaseJSNativeFunction f, final Object... variables) {
			if (USE_FAST_RANDOM)
				return RandomUtil.random();
			return Math.random();
		}
	};
	public static final BaseJSNativeFunction pow = new BaseJSNativeFunction("pow", "x1", "x2") {

		@Override
		public Object invoked(BaseJSEnvironment e, BaseJSNativeFunction f, final Object... variables) {
			if (variables == null || variables.length < 2)
				throw new UnsupportedOperationException();
			final double x1 = ((Number) variables[0]).doubleValue();
			final double x2 = ((Number) variables[1]).doubleValue();
			return Math.pow(x1, x2);
		}
	};
	/** Non-standard */
	public static final BaseJSNativeFunction iadd = new BaseJSNativeFunction("iadd", "x1", "x2") {

		@Override
		public Object invoked(BaseJSEnvironment e, BaseJSNativeFunction f, final Object... variables) {
			if (variables == null || variables.length < 2)
				throw new UnsupportedOperationException();
			final double x1 = ((Number) variables[0]).doubleValue();
			final double x2 = ((Number) variables[1]).doubleValue();
			return (int) (x1 + x2);
		}
	};
	public static final BaseJSNativeFunction imul = new BaseJSNativeFunction("imul", "x1", "x2") {

		@Override
		public Object invoked(BaseJSEnvironment e, BaseJSNativeFunction f, final Object... variables) {
			if (variables == null || variables.length < 2)
				throw new UnsupportedOperationException();
			final double x1 = ((Number) variables[0]).doubleValue();
			final double x2 = ((Number) variables[1]).doubleValue();
			return (int) (x1 * x2);
		}
	};
	public static final BaseJSNativeFunction abs = new BaseJSNativeFunction("imul", "x1") {

		@Override
		public Object invoked(BaseJSEnvironment e, BaseJSNativeFunction f, final Object... variables) {
			if (variables == null || variables.length < 2)
				throw new UnsupportedOperationException();
			final double x1 = ((Number) variables[0]).doubleValue();
			return Math.abs(x1);
		}
	};

	private static Map<String, BaseJSObject> OBJECTS = new ConcurrentHashMap<String, BaseJSObject>();
	static {
		if (OBJECTS.isEmpty()) {
			OBJECTS.put("PI", PI);
			OBJECTS.put("E", E);
			OBJECTS.put("random", random);
			OBJECTS.put("pow", pow);
			OBJECTS.put("iadd", iadd);
			OBJECTS.put("imul", imul);
			OBJECTS.put("abs", abs);
		}
	}

	public BaseJSMath() {
		super("Math", Collections.unmodifiableMap(OBJECTS));
	}
}
